﻿// (c)2010 Knihovnik
// This file is licensed under GNU GPL v2 license, see more at http://www.gnu.org/licenses/gpl-2.0.html
namespace vKapse.DDTool.Visual
{

	#region Using

	using System;
	using System.Diagnostics;
	using System.Drawing;
	using System.Drawing.Imaging;
	using System.IO;
	using System.Net;
	using System.Net.Mail;
	using System.Text;
	using System.Windows.Forms;
	using Res = Z2.Editor.Properties;

	#endregion

	/// <summary>
	/// Formulář pro zobrazování výjimek v aplikaci
	/// </summary>
	public partial class ExceptionView : Form
	{

		#region Members

		private static volatile object _syncRoot = new object();

		#endregion

		#region Const

		//
		// Please, don't be an asshole and do not change this password, ok? :)
		//

		private const string SMTP_SERVER = "smtp.gmail.com";
		private const string DEV_EMAIL = "vkapse.davecz@gmail.com";
		private const string MAIL_FROM = "vkapse.databasedesigner@gmail.com";
		private const string MAIL_PASS = "5kapse.500atabase500es1gner"; 
		private const string TABLE_START = "<table>";
		private const string TABLE_END = "</table>";
		private const string TABLE_ROW = "<tr><td>{0}:</td><td>{1}</td></tr>";
		private const string HTML_LINE = "{0}<br/>";

		#endregion

		#region Members

		private Exception m_exception;

		#endregion

		#region Constructor

		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="e">Výjimka</param>
		public ExceptionView(Exception e)
		{
			this.InitializeComponent();

			this.m_exception = e;
			this.picImage.Image = SystemIcons.Warning.ToBitmap();
			this.SetTitles();
		}

		#endregion

		#region Event Handling

		private void btnSend_Click(object sender, EventArgs e)
		{
			this.btSend.Enabled = false;
			MethodInvoker invoker = new MethodInvoker(delegate
			{
				// Nastavení SMTP pro Gmail
				SmtpClient client = new SmtpClient(ExceptionView.SMTP_SERVER, 587);
				client.EnableSsl = true;
				client.DeliveryMethod = SmtpDeliveryMethod.Network;

				client.Credentials = new NetworkCredential(ExceptionView.MAIL_FROM, ExceptionView.MAIL_PASS);

				MailMessage message = new MailMessage();
				message.To.Add(ExceptionView.DEV_EMAIL);
				message.Subject = Res.Resources.Exception;

				message.From = new MailAddress(ExceptionView.MAIL_FROM);
				message.IsBodyHtml = true;
				message.Priority = MailPriority.Normal;
				message.Body = this.GetExceptionData();

				try
				{
					client.Send(message);
				}
				catch (Exception ex)
				{
					Debug.Write(ex);
				}
				finally
				{
					this.Invoke(new MethodInvoker(delegate 
						{
							if(!this.IsDisposed)
							{
								this.Close();
							}
						}));
				}
			});

			invoker.BeginInvoke(null, null);
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void btCopyToClipboard_Click(object sender, EventArgs e)
		{
			Clipboard.SetText(this.ConvertText(this.m_exception));
		}

		#endregion

		#region Methods

		/// <summary>
		/// Metoda zobrazí exception dialog
		/// </summary>
		/// <param name="ex"></param>
		public static void Show(Exception ex)
		{
			lock (_syncRoot)
			{
				using (ExceptionView form = new ExceptionView(ex))
				{
					form.ShowDialog();
				}
			}
		}

		/// <summary>
		/// Konverze vyjímky na řetezec, který se pošle v tělě mailu
		/// </summary>
		/// <param name="e">Vyjímka</param>
		/// <remarks>Použil jsem rekurzivní funkci, protože vyjímka může mít ještě vnitřní vyjímku.</remarks>
		/// <returns>Text výjimky</returns>
		private string GetExceptionData()
		{
			StringBuilder builder = new StringBuilder();
			builder.Append(ExceptionView.TABLE_START);
			builder.AppendFormat(ExceptionView.TABLE_ROW, Res.Resources.Exception, this.m_exception.GetType().Name);
			builder.AppendFormat(ExceptionView.TABLE_ROW, Res.Resources.Message, this.m_exception.Message);
			builder.AppendFormat(ExceptionView.TABLE_ROW, Res.Resources.Module, this.m_exception.Source);
			builder.AppendFormat(ExceptionView.TABLE_ROW, Res.Resources.StackTrace, this.m_exception.StackTrace);
			builder.AppendFormat(ExceptionView.TABLE_ROW, Res.Resources.Method, this.m_exception.TargetSite.ToString());

			if (!string.IsNullOrEmpty(this.tbUserMessage.Text))
			{
				builder.AppendFormat(ExceptionView.TABLE_ROW, Res.Resources.UserMessage, this.tbUserMessage.Text);
			}
			builder.Append(ExceptionView.TABLE_END);
			if (this.m_exception.InnerException == null)
			{
				builder.AppendFormat(ExceptionView.HTML_LINE, Res.Resources.NoInnerExceptions);
			}
			else
			{
				builder.AppendFormat(ExceptionView.HTML_LINE, Res.Resources.InnerExceptions);
				builder.Append(this.GatherInnerExceptions(this.m_exception.InnerException));
			}

			return builder.ToString();
		}

		/// <summary>
		/// Metoda "posbírá" data vnitřních výjimek
		/// </summary>
		/// <param name="exception"><see cref="Exception"/></param>
		/// <returns>Text. data</returns>
		private string GatherInnerExceptions(Exception exception)
		{
			StringBuilder builder = new StringBuilder();
			builder.AppendFormat(ExceptionView.HTML_LINE, exception.ToString());
			if (exception.InnerException != null)
			{
				builder.Append(this.GatherInnerExceptions(exception.InnerException));
			}
			return builder.ToString();
		}

		/// <summary>
		/// Zkonvertuje data výjimky na čistý text 
		/// </summary>
		/// <param name="ex"><see cref="Exception"/></param>
		/// <returns>Text</returns>
		private string ConvertText(Exception ex)
		{
			StringBuilder builder = new StringBuilder();
			builder.AppendLine(ex.GetType().Name);
			builder.AppendLine(ex.Message);
			builder.AppendLine(ex.Source);
			builder.AppendLine(ex.StackTrace);
			builder.AppendLine(ex.TargetSite.ToString());
			builder.AppendLine(this.tbUserMessage.Text);

			return builder.ToString();
		}

		/// <summary>
		/// Nastavení textů formuláře
		/// </summary>
		private void SetTitles()
		{
			this.tbMessage.Text = this.m_exception.Message;
			this.tbModule.Text = this.m_exception.Source;
			this.tbMethod.Text = this.m_exception.TargetSite.ToString();
			this.tbUserMessage.Text = string.Empty;

			this.Text = Res.Resources.Exception;
			this.lbException.Text = Res.Resources.UnhandledExceptionOccured;
			this.gbInfo.Text = Res.Resources.ExceptionInfo;
			this.lbMessage.Text = string.Format("{0}:", Res.Resources.Message);
			this.lbModule.Text = string.Format("{0}:", Res.Resources.Module);
			this.lbMethod.Text = string.Format("{0}:", Res.Resources.Method);
			this.lbUserMessage.Text = string.Format("{0}:", Res.Resources.UserMessage);
			this.btSend.Text = Res.Resources.ExceptionSend;
			this.btCancel.Text = Res.Resources.CloseForm;
		}

		#endregion

	}
}
